import React, { useEffect, useRef } from 'react';
import { Terminal } from 'xterm';
import { AttachAddon } from './AttachAddon';
import { FitAddon } from 'xterm-addon-fit';
import 'xterm/css/xterm.css';
import './App.css';

// new TextEncoder().encode()
// new TextDecoder().decode()

function App() {
    const dom = useRef();
    const term = useRef();
    const wsRef = useRef();
    const fitAddon = useRef();
    const attachAddon = useRef();
    const timer = useRef();

    useEffect(() => {
        function onResize() {
            fitAddon.current?.fit();
            term.current?.scrollToBottom();
        }
        function onOpen() {
            timer.current = setInterval(() => {
                wsRef.current?.send('ping');
            }, 10 * 1000);
        }
        function onClose(event) {
            term.current?.writeln(event.data || 'service closed');
            if (timer.current) {
                clearInterval(timer.current);
                timer.current = null;
            }
        }
        // term
        term.current = new Terminal({
            cursorBlink: true,
            // scrollback: Infinity,
        });
        term.current.open(dom.current);
        // fit
        fitAddon.current = new FitAddon();
        term.current.loadAddon(fitAddon.current);
        fitAddon.current.fit();
        // wsRef
        const { rows, cols } = term.current;

        const socketURL = `ws://localhost:8001/socket?rows=${rows}&cols=${cols}`;
        wsRef.current = new WebSocket(socketURL);
        wsRef.current.addEventListener('open', onOpen);
        wsRef.current.addEventListener('close', onClose);
        // attach
        attachAddon.current = new AttachAddon(wsRef.current, {
            bidirectional: false,
        });
        term.current.loadAddon(attachAddon.current);

        term.current.onData((data) => {
            if (!attachAddon.current._checkOpenSocket()) {
                return;
            }
            const reg = new RegExp('[\\u4E00-\\u9FFF]+', 'g');
            if (reg.test(data)) {
                attachAddon.current?._socket?.send(data);
            } else {
                attachAddon.current?._socket?.send(data);
            }
        });

        // resize
        term.current?.onResize(({ cols, rows }) => {
            wsRef.current?.send(JSON.stringify({ resize: [cols, rows] }));
        });
        window.addEventListener('resize', onResize);

        return () => {
            if (timer.current) {
                clearInterval(timer.current);
                timer.current = null;
            }
            // 取消resize事件
            window.removeEventListener('resize', onResize);
            // 关闭ws
            wsRef.current?.removeEventListener('open', onOpen);
            wsRef.current?.removeEventListener('close', onClose);
            wsRef.current?.close();
            wsRef.current = null;
            // 销毁attachAddon
            attachAddon.current?.dispose();
            attachAddon.current = null;
            // 销毁fitAddon
            fitAddon.current?.dispose();
            fitAddon.current = null;
            // 销毁term
            term.current?.dispose();
            term.current = null;
        };
    }, []);

    return (
        <div
            className='App'
            ref={dom}
        ></div>
    );
}

export default App;
